/*
 * pattern.h
 *
 *  Created on: Mar 24, 2011
 *      Author: cookiemouse
 */

#ifndef PATTERN_H_
#define PATTERN_H_

#include<iostream>
#include<ostream>
#include<vector>
#include<set>
#include<sstream>
#include<math.h>

using namespace std;

inline string itos(int i) {
	string tmp;
	stringstream ss;
	ss << i;
	ss >> tmp;
	return tmp;
}

class PatternNode {

	friend class Pattern;
	friend class aprioriAll;
	int x, y, gap;

public:
	PatternNode(int myx, int myy, int time) {
		this->x = myx;
		this->y = myy;
		this->gap = time;
	}
	PatternNode() {
	}
	~PatternNode() {
	}
	PatternNode(const PatternNode &other) {
		this->x = other.x;
		this->y = other.y;
		this->gap = other.gap;
	}
	bool isNeighbor(const PatternNode &node) {
		return fabs(this->x - node.x) <= 1 && fabs(this->y - node.y) <= 1;
	}
	bool operator==(const PatternNode &node) {
		return (this->x == node.x && this->y == node.y && this->gap == node.gap);
	}
	bool samelocation(const PatternNode &node) {
		return this->x == node.x && this->y == node.y;
	}

	string tostring() {
		/*string tmp;
		 tmp= "("+itos(x)+","+itos(y)+")";
		 tmp+=itos(gap);
		 return tmp;*/
		stringstream ss;
		string tmp;
		ss << *this;
		ss >> tmp;
		return tmp;
	}
	friend ostream &operator<<(ostream &ios, const PatternNode &node) {
		ios << "(" << node.x << "," << node.y << ")";
		if (node.gap != -1) {
			ios << node.gap;
		}
		return ios;
	}
};

class Pattern {
	friend class aprioriAll;
	vector<PatternNode> nodes;
	string mystr;
	string mysubstr;

public:
	Pattern() {
		mystr.clear();
		mysubstr.clear();
	}

	~Pattern() {
		nodes.clear();
	}
	void addNode(PatternNode node) {
		nodes.push_back(node);
	}
	int length() {
		return nodes.size();
	}

	string firstKMinus1() {
		if (mysubstr.length() == 0) {
			for (int i = 0; i < length()-1; i++) {
				stringstream ss;
				string t;
				PatternNode curNode = nodes.at(i);
				if (i==length()-2){
					curNode.gap = -1;
				}
				ss << curNode;
				ss >> t;
				mysubstr += t;
			}
		}
		//cout <<"mysubstr:" << mysubstr << endl;
		return mysubstr;
	}

	Pattern* patternGrow(Pattern &pattern) {
		Pattern* merged = new Pattern();
		string p2Str = pattern.tostring();
		string p1Str = this->tostring();
//		Pattern* small1 = this->firstKMinus1();
		string small1str = this->firstKMinus1();
//		Pattern* small2 = pattern.firstKMinus1();
		string small2str = pattern.firstKMinus1();
		bool mergeable = false;
		if (p1Str.find(small2str) < p1Str.length() && p1Str.find(small2str) > 0) {
			merged->nodes.push_back(nodes.at(0));
			for (int i = 0; i < length(); i++) {
				merged->nodes.push_back(pattern.nodes.at(i));
			}
		} else if (p2Str.find(small1str) < p2Str.length() && p2Str.find(
				small1str) > 0) {
			merged->nodes.push_back(pattern.nodes.at(0));
			for (int i = 0; i < length(); i++) {
				merged->nodes.push_back(nodes.at(i));
			}
		}
//		delete small1;
//		delete small2;
		return merged;
	}

	friend ostream &operator<<(ostream &ios, Pattern &pattern) {
		for (int i = 0; i < pattern.length(); i++) {
			ios << (pattern.nodes.at(i));
		}
		return ios;
	}
	string tostring() {
		if (mystr.length() == 0) {
			//			string tmp;
			for (int i = 0; i < length(); i++) {
				stringstream ss;
				string t;
				ss << (nodes.at(i));
				ss >> t;
				mystr += t;
			}
		}
		return mystr;
	}

};

#endif /* PATTERN_H_ */
